home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / FORTH / FORTHMAC / OLD / DOCS / !Forthmacs.docs.ascii.arm_hardw next >
Encoding:
Text File  |  1996-06-15  |  14.1 KB  |  343 lines

  1.  
  2. Hardware Diagnostics in Forth
  3. *****************************
  4.  
  5.  
  6. fine tools ...
  7. ==============
  8.  
  9. Forth has been long used for large numbers of hardware projects, both 
  10. commercial and private.  RISC OS Forthmacs is exceptionally stable and 
  11. needs only very few resources on the computer.  
  12.  
  13. Here's how you can write Forth programs to diagnose your hardware.  
  14. The programs can range from very simple things like reading a register 
  15. to very complicated things like performing communications protocols.  
  16. Each higher level of tests can build on the lower levels.  At any 
  17. time, you can interactively execute any part of the test, without 
  18. having to build a command interpreter into your program.  
  19.  
  20. This document describes how to do very simple things interactively.  
  21. It is also possible to save your work in a file and to make sequences 
  22. of tests run automatically.  
  23.  
  24.  
  25. Warning
  26. =======
  27.  
  28. The examples in the rest of this document assume that you are running 
  29. on a stand-alone system, and that there really are I/O devices located 
  30. at the addresses mentioned.  If you are running RISC OS Forthmacs 
  31. under RISC OS or Unix, both won't allow you to access device 
  32. registers, so the examples in this paper will cause a core dump of the 
  33. Forth process.  
  34.  
  35. In fact, most of these examples assume that you are trying to debug a 
  36. board whose registers begin at virtual address (hex) 3340000.  In RISC 
  37. OS computers this would be a Simple Exp.  card with fast access, this 
  38. might not be right for your system, so please pick an address for your 
  39. system where you know there is some device or memory.  
  40.  
  41.  
  42. Getting started
  43. ===============
  44.  
  45. The way to get Forth running on your machine is system-dependent, so 
  46. we won't go into that topic here.  We assume that you have already 
  47. figured out how to get Forth going, and that it is prompting you with 
  48. 'ok' .  
  49.  
  50.  
  51. Poking at registers
  52. ===================
  53.  
  54. The first hurdle to cross when debugging a new board is usually 
  55. reading and writing the device registers.  With most programming 
  56. environments or monitors, if the register doesn't work, you are stuck.  
  57. Not so with Forth.  Suppose that you have a 32-bit register at address 
  58. (hex) 3340000.  You can read it with: 
  59.       3340000  @  .
  60. @ says to read a 32-bit word from the preceding address.  . says to 
  61. print the result.  @ is pronounced "fetch".  In general, the @ symbol 
  62. is pronounced 'fetch' in Forth terminology.  There must be one or more 
  63. spaces separating symbols! 
  64.  
  65. Note: The Forth parser is really simple; it just grabs the next 
  66. sequence of non-blank characters (called a 'word' in the jargon) from 
  67. the terminal and looks up that word in its internal dictionary.  If it 
  68. finds the word, it executes some associated code.  If it doesn't find 
  69. the word, it tries to parse the word as a number.  If that fails, it 
  70. complains.  
  71.  
  72. Note: @ accesses a 32-bit location, the address must be long-aligned.  
  73. If your device is 8 bits wide, use C@ in this and future examples; 
  74. also use C! instead of ! .  
  75.  
  76. There is a problem with 16-bit registers in ARM based computers, ARM 
  77. cpus don't support word-wide 16-bit data access.  You can use W@ and 
  78. W! but both instructions use two byte-wide memory accesses, so this 
  79. might not be what you wanted.  Or you use 32-bit normal accesses and 
  80. mask-off the other 
  81.  
  82. The most likely result of trying this exercise on a prototype 
  83. peripheral board is that the board won't respond to the cycle, so the 
  84. CPU will get a bus error, print a message, and abort back to Forth.  
  85.  
  86. On a working device, instead of getting an error, Forth will display 
  87. the contents of the register you accessed.  
  88.  
  89.  
  90. Scope Loops
  91. ===========
  92.  
  93. No, you don't have to get out your assembly language reference manual 
  94. and try to figure out how to poke in a tiny loop.  Here's how to make 
  95. a loop: 
  96.  
  97. 3340000 constant reg-addr
  98. : test   begin  reg-addr @    drop  key? until  ;
  99.  
  100. This creates a loop which will repeatedly read a register at location 
  101. 3340000.  BEGIN ...  KEY? UNTIL means to keep doing everything between 
  102. the BEGIN and the KEY? until a key is typed on the keyboard.  The DROP 
  103. is needed to get rid of the value that was read from the register, 
  104. which is left on a stack.  That stack would eventually overflow if not 
  105. for the DROP. The loop is called TEST , and it is a new command which 
  106. you have just created, you could have called it anything you wanted, 
  107. instead of TEST .  
  108.  
  109. Remember that there will be an address exception if the physical 
  110. address hasn't been accepted by the MMU.  Now you can try the loop.  
  111.     test
  112.  
  113. In general, the way to execute a Forth command is by typing its name.  
  114.  
  115. So now the machine is sitting there banging away at your register.  
  116. You can try to find a scope that still has some probes attached and 
  117. figure out why your register isn't responding.  
  118.  
  119. It wasn't actually necessary to have given the loop a name.  You could 
  120. have just typed: 
  121.     begin  reg-addr @ drop  again
  122.  
  123. This is different from almost all Forth dialects, RISC OS Forthmacs 
  124. knows about temporary compilation and forgets about the compiled code 
  125. afterwards.  
  126.  
  127. However, by giving the command a name, you save it away so you can use 
  128. it later, just by typing the name.  It's not saved on disk, just in 
  129. memory, so if you reboot, the new command will be lost.  It would be 
  130. nice if you could save your work on disk, but in a lot of stand-alone 
  131. debugging cases there is no disk on the machine.  To learn how you can 
  132. save your work, read the "Creating Stand-Alone Forths" chapter 
  133.  
  134.  
  135. Writing to registers
  136. ====================
  137.  
  138. Now that you can read your register, no doubt you want to write to it 
  139. too.  
  140.     1234 reg-addr !
  141. writes the 32-bit word 1234 (hex) to the address left by the word 
  142. REG-ADDR (which we defined earlier).  If you want to write a byte 
  143. instead of a 32-bit word, use C!. 
  144.     reg-addr @ .
  145. reads back the register and prints the value, so you can verify that 
  146. the write actually worked.  
  147.  
  148.  
  149. Do Loops
  150. ========
  151.  
  152. An obvious thing to do now is to write a bunch of different values to 
  153. the register and see if they all work.  
  154.  
  155. : test-loop
  156.    ffff 0  do
  157.       i  reg-addr !     ( write a value to the register )
  158.       reg-addr @        ( read it back )  ( register value on stack )
  159.       i <>   ( see if the value read back is different from the one written )
  160.       if    ." Error - wrote "    i .    ." read "   reg-addr @ .  cr
  161.       then
  162.    loop ;
  163.  
  164. The indentation is optional.  If you were writing this test on-the-fly 
  165. while sitting in the lab, you would probably not bother with 
  166. indentation.  Similarly, everything inside parentheses is a comment 
  167. and may be omitted.  When you are writing Forth programs to save 
  168. (presumably using a Unix editor), please don't omit the comments or 
  169. the indentation, because that would make your work hard to understand 
  170. later.  
  171.  
  172. How does this test-loop work? Let's go over it line-by-line.  'ffff 0' 
  173. are the arguments to the DO ...  LOOP construct.  The loop starts at 0 
  174. and ends when the loop index reaches (hex) ffff.  The last time 
  175. through the loop, the index has the value (hex) fffe.  The firs thing 
  176. inside the loop is 'i reg-addr !' .  Previously we used the literal 
  177. number '1234' as the value to store into location reg-addr.  This time 
  178. we use the loop index I .  The loop index is 'always' called I .  If 
  179. you use nested loops, the index of the next outer loop is called J .  
  180.  
  181. The next thing we do inside the loop is read back the register.  
  182. Previously we printed the value as soon as we read it; this time we 
  183. will let the program look at and decide if it's okay.  But where is 
  184. the value kept? It's on the stack, just like on an HP calculator.  In 
  185. fact almost every operator in Forth takes its operands from the stack 
  186. and leaves its results on the same stack.  I will assume that this 
  187. concept is familiar to you; if it isn't, let me know and I will either 
  188. explain it to you or loan you a book which does so.  Anyway, the 
  189. register value is now sitting on the stack.  The next thing we do is 
  190. compare that value to the loop index I .  The operator <> (not-equal) 
  191. compares the top two things on the stack and leaves true if they are 
  192. not equal or false if they are equal.  
  193.  
  194. If the numbers are equal, all is well.  If they are different, we need 
  195. to print an error message.  That is where the IF ...  THEN construct 
  196. comes in.  Here is the strange part: The stuff you want to do if the 
  197. condition is true goes BETWEEN IF and THEN, not after THEN as one 
  198. would expect.  This is unfortunate, but it is not the end of the 
  199. world.  The condition that is tested comes BEFORE the IF; in this case 
  200. the condition is the true/false value left on the stack by the <> 
  201. operator.  If this seems strange to you, consider that it is very 
  202. simple, yet completely general.  It is also possible to specify an 
  203. ELSE clause (details later).  
  204.  
  205. The only thing remaining for this test-loop is to describe how the 
  206. error message is printed.  The construct '." ... "' , pronounced 
  207. "dot-quote, prints whatever is inside the quotes.  The first space 
  208. after the first quote is mandatory and is not printed.  Any subsequent 
  209. spaces before the next quote are part of the string and are printed.  
  210. Next we print the loop index with I . .  As you have probably guessed, 
  211. . just means print whatever number is on the stack.  Next we print 
  212. another string, followed by the value read back from the register.  
  213. Finally, CR prints a carriage-return and linefeed.  
  214.  
  215.  
  216. Extensibility
  217. =============
  218.  
  219. Earlier we saw how to make a word called 'test' which could then be 
  220. executed by typing its name.  Once you have made a word, you can then 
  221. use it as part of another word, thus building on top of your previous 
  222. work.  For example, suppose that there is a dma address register on 
  223. your board, and that its address is (hex) 3340804.  You can define a 
  224. word to store a value into that register as follows: 
  225.     : dma!  3340804 !  ;
  226. This defines a new word called DMA! which takes an argument and stores 
  227. it into the prescribed location.  This word can be used as: 
  228.     f00000 dma!
  229. which will store f00000 into the dma register.  Now, suppose that as 
  230. part of a test, you need to automatically set the dma register.  You 
  231. can use your word dma! as part of another word.  
  232.     : init-dma  f00000 dma!  ;
  233. This is a trivial example, but it serves to illustrate the style of 
  234. building up your application in small incremental steps.  Don't 
  235. hesitate to build words which only have a few components; the overhead 
  236. of calling a word from one at higher level is quite small, and the 
  237. advantages of small words are many (readability, ease of debugging, 
  238. possibility of reuse).  
  239.  
  240.  
  241. Variables
  242. =========
  243.  
  244. Define a variable with 
  245.     variable foo
  246. The new variable FOO has space for a 32-bit word.  Put a number in the 
  247. variable with: 
  248.     129876 foo !
  249. and get it back with 
  250.     foo @
  251. The number to be stored is taken from the stack, and the number 
  252. fetched is left on the stack.  When you typed the 129876, that number 
  253. was actually left on the stack, and FOO ! picked it up and put in the 
  254. variable foo.  FOO @ retrieved it from the variable and returned it to 
  255. the stack.  
  256.  
  257.  
  258. Constants
  259. =========
  260.  
  261. A constant is a symbolic name for a number.  In other words, when you 
  262. type the name of a constant, it just leaves its number on the stack.  
  263. One way of making a constant is the obvious: 
  264.     : mem-base  100000  ;
  265. Now the word mem-base is equivalent to the number 100000.  A slightly 
  266. more efficient form of this is: 
  267.     100000 constant mem-base
  268. A word defined with CONSTANT will execute somewhat faster than one 
  269. defined the other way (but you would probably never notice the 
  270. difference).  
  271.  
  272.  
  273. C Language Analogies
  274. ====================
  275.  
  276.         C                               Forth
  277. while( condition ) {                    BEGIN  condition  WHILE
  278.         loop-body                               loop-body
  279. }                                       REPEAT
  280. do {                                    BEGIN
  281.         loop-body                               loop-body
  282. until ( condition )                     condition  UNTIL
  283. for( i=start_value;                     end_value
  284.       i<end_value;                      start_value
  285.       i += increment ) {                DO
  286.         loop-body                               loop-body
  287. }                                       increment +LOOP
  288. for( i=start value;                     end value
  289.       i<end value;                      start value
  290.       i++ ) {                           DO
  291.         loop-body                               loop-body
  292. }                                       LOOP
  293. if ( condition ) {                      condition
  294.         true_clause                     IF      true_clause
  295. } else {                                ELSE    false_clause
  296.         false_clause                    THEN
  297. }
  298. if ( condition ) {                      condition
  299.         true_clause                     IF      true_clause
  300. }                                       THEN
  301.  
  302. Forth Notes: 
  303.  
  304. "condition" is any sequence of Forth words that has the effect of 
  305. leaving a number on the stack.  If the number the stack is 0, the 
  306. condition value is false, otherwise it is true.  
  307.  
  308. Within a do loop, the word I will put the loop index on the stack.  
  309.  
  310.  
  311. One More Thing ...
  312. ==================
  313.  
  314. You may want to do a scope loop which can be easily interrupted.  You 
  315. can always abort back to RISC OS Forthmacs with Shift-Ctrl-F12.  A 
  316. nicer way, however, is the following: 
  317.     : scope-loop   begin  1234 reg-addr !  key? until  ;
  318. This word will continuously write 1234 to location 'reg-addr' until 
  319. you type any key.  The word KEY? returns true (which happens to be 
  320. equal to -1) if a key has been depressed, and false (0) if not.  
  321.  
  322.  
  323. Other Wonderful Features
  324. ========================
  325.  
  326. Forth includes, among other things, a resident assembler, so you can 
  327. write little bits of assembly code if you need to.  It has a built-in 
  328. visual line editor, so you can edit command lines as you type them.  
  329. There are packages for defining structures and bit fields, similar to 
  330. C.  A built-in decompiler allows you to interactively decompile any 
  331. Forth word that you have previously defined.  Try typing SEE followed 
  332. by the name of any Forth command, or any Forth word you have already 
  333. defined.  
  334.  
  335.  
  336. Line Editing
  337. ============
  338.  
  339. While you are typing a Forth command line, you can move around in the 
  340. line and edit it.  Have a look at the chapter 
  341. TYPING FORTH COMMAND LINES .  
  342.  
  343.